//
// Created by DELL on 2021/3/20.
//

#ifndef SYLAR_SERVLET_H
#define SYLAR_SERVLET_H

#include "http/http.h"
#include "http/http_session.h"
#include "mutex.h"
#include <functional>
#include <unordered_map>

namespace sylar {
    namespace http {
        class Servlet {
        public:
            using ptr = std::shared_ptr<Servlet>;

            explicit Servlet(const std::string &name)
                    : m_name(name) {}

            virtual ~Servlet() {}

            virtual int32_t handle(HttpRequest::ptr request, HttpResponse::ptr response, HttpSession::ptr session) = 0;

            const std::string &getName() const { return m_name; }

        protected:
            std::string m_name;
        };

        class FunctionServlet : public Servlet {
        public:
            using ptr = std::shared_ptr<FunctionServlet>;
            using callback = std::function<int32_t(HttpRequest::ptr request,
                                                   HttpResponse::ptr response,
                                                   HttpSession::ptr session)>;

            explicit FunctionServlet(callback cb);

            int32_t handle(HttpRequest::ptr request,
                           HttpResponse::ptr response,
                           HttpSession::ptr session) override;

        private:
            callback m_cb;
        };

        class ServletDispatch : public Servlet {
        public:
            using ptr = std::shared_ptr<ServletDispatch>;
            using RWMutexType = RWMutex;

            ServletDispatch();

            int32_t handle(HttpRequest::ptr request,
                           HttpResponse::ptr response,
                           HttpSession::ptr session) override;


            void addServlet(const std::string &uri, Servlet::ptr servlet);

            void addServlet(const std::string &uri, FunctionServlet::callback cb);

            void addGlobServlet(const std::string &uri, Servlet::ptr servlet);

            void addGlobServlet(const std::string &uri, FunctionServlet::callback cb);

            void delServlet(const std::string &uri);

            void delGlobServlet(const std::string &uri);

            Servlet::ptr getDefault() const { return m_default; }

            void setDefault(Servlet::ptr v) { m_default = v; }

            Servlet::ptr getServlet(const std::string &uri);

            Servlet::ptr getGlobServlet(const std::string &uri);

            Servlet::ptr getMatchedServlet(const std::string &uri);

        private:
            RWMutexType m_mutex;
            /// 精准匹配servlet MAP
            /// uri(/sylar/xxx) -> servlet
            std::unordered_map<std::string, Servlet::ptr> m_data;
            /// 模糊匹配servlet 数组
            /// uri(/sylar/*) -> servlet
            std::vector<std::pair<std::string, Servlet::ptr>> m_globs;
            /// 默认servlet，所有路径都没匹配到时使用
            Servlet::ptr m_default;
        };

        class NotFoundServlet : public Servlet {
        public:
            using ptr = std::shared_ptr<NotFoundServlet>;

            explicit NotFoundServlet(const std::string &name);

            int32_t handle(HttpRequest::ptr request,
                           HttpResponse::ptr response,
                           HttpSession::ptr session) override;

        private:
            std::string m_name;
            std::string m_content;
        };
    }
}
#endif //SYLAR_SERVLET_H
